package sg.edu.nus.iss.cerberus.wizard;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;

import sg.edu.nus.iss.cerberus.actions.FolderCreation;
import sg.edu.nus.iss.cerberus.engine.JUnit4TestClassBuilder;
import sg.edu.nus.iss.cerberus.engine.TestClassDirector;
import sg.edu.nus.iss.cerberus.extensionpoint.INewTestCaseWizardPage;
import sg.edu.nus.iss.cerberus.preferences.Preferences;
import sg.edu.nus.iss.cerberus.util.BaseTools;
import sg.edu.nus.iss.cerberus.util.CerberusConstants;
import sg.edu.nus.iss.cerberus.util.StringConstants;
import sg.edu.nus.iss.cerberus.wizard.*;


public class NewTestCaseWizard extends NewClassyWizard {
	private final IJavaProject project;
	private final Preferences preferences;
	private final NewTestCaseWizardParticipatorManager participatorManager;

	private TestFixturePage pageOne;
	private NewTestCaseWizardContext context;
	private NewTestCaseWizardComposer wizardComposer;
	private FolderCreation fc;

	private MethodTestDataPage inputdataPage;

	public NewTestCaseWizard(final IType element) {
		super(element);
		this.project = element.getJavaProject();
		this.preferences = Preferences.getInstance();
		this.participatorManager = new NewTestCaseWizardParticipatorManager();
		this.fc = null;
	}

	@Override
	public void addPages() {
		//this.pageTwo = new NewTestCaseWizardPageTwo();
		//this.pageOne = new CerberusWizardPageOne(this.pageTwo, project);
		this.pageOne = new TestFixturePage(project);
		this.pageOne.setWizard(this);

		this.pageOne.init(new StructuredSelection(getType()));
		this.inputdataPage = new MethodTestDataPage(
				CerberusConstants.WIZARD_TITLE_TEXT, pageOne.getTestGenData());
		this.inputdataPage.setWizard(this);
		setSelection(pageOne.getSelection());
		try {
			fc = new FolderCreation(pageOne.getSelection());
			fc.createTestFolder();
			fc.createTestPackage();
		} catch (Exception e) {
			e.printStackTrace();
		}

		this.context = new NewTestCaseWizardContext(getType(),
				fc.getPackageFrag());
		this.wizardComposer = participatorManager.createWizardComposer(context);
		this.wizardComposer.registerBasePage(
				INewTestCaseWizardPage.TEST_CASE_PAGE, this.pageOne);
		this.wizardComposer.registerExtensionPages(this.inputdataPage);
		this.wizardComposer.compose(this);
	}

	@Override
	public boolean performFinish() {
		try {
			
			pageOne.setTestGenData(inputdataPage.updateTestGenData());
			
			super.performFinish();
		
			getDialogSettings().put(getPackageFragmentRootKey(),
					fc.getPackageFragRoot().getHandleIdentifier());
		} catch (Exception e) {
			System.out.println(e);
		}
		return true;
	}

	private String getPackageFragmentRootKey() {
		return super.getClass().getName() + ".packageFragmentRoot";
	}

	@Override
	public void createPageControls(Composite pageContainer) {
		super.createPageControls(pageContainer);
		// Eclipse 3.1.x does not support junit 4
		try {
			this.pageOne.setJUnit4(true, true);
		} catch (NoSuchMethodError error) {
		}

		String testSuperClass = getTestSuperClass();
		if (testSuperClass != null)
			this.pageOne.setSuperClass(testSuperClass, true);

		this.pageOne.setTypeName(getTestCaseClassName(), true);
		this.pageOne.setPackageFragmentRoot(fc.getPackageFragRoot(), true);
	}

	private String getTestCaseClassName() {
		String classUnderTest = pageOne.getClassUnderTestText();

		if (classUnderTest.length() == 0)
			return StringConstants.EMPTY_STRING;

		return getFirstPrefix() + Signature.getSimpleName(classUnderTest);// +
																			// getFirstSuffix();
	}

	private String getFirstPrefix() {
		String[] prefixes = preferences.getPrefixes(project);
		String prefix = StringConstants.EMPTY_STRING;
		if (prefixes.length > 0) {
			prefix = prefixes[0];
		}
		return prefix;
	}

	private String getTestSuperClass() {
		String result = this.preferences.getTestSuperClass(project);

		if (BaseTools.isStringTrimmedEmpty(result)
				&& preferences.shouldUseJunit3Type(project))
			return null;

		return result;
	}

	@Override
	protected IPackageFragmentRoot getSourceFolderForUnitTest() {
		return preferences.getJUnitSourceFolder(this.project);
	}

	@Override
	public IType createClass() throws CoreException, InterruptedException {
		this.pageOne.createType(new NullProgressMonitor());
		return this.pageOne.getCreatedType();
	}

	@Override
	protected IPackageFragmentRoot getPackageFragmentRoot() {
		return fc.getPackageFragRoot();
	}

	@Override
	protected void typeCreated(IType createdType) {
		super.typeCreated(createdType);

		NewTestCaseWizardContext ctxt = getContext();
		ctxt.setCreatedTestCase(createdType);
		participatorManager.testCaseCreated(ctxt);
	}

	private NewTestCaseWizardContext getContext() {
		if (context == null) {
			throw new IllegalStateException(
					"Context is null. It should not be retrieved before addPages() has been called.");
		}
		return context;
	}

	@Override
	public boolean performCancel() {
		boolean cancelationAccepted = super.performCancel();
		if (cancelationAccepted) {
			participatorManager.testCaseCreationCanceled(getContext());
		}
		return cancelationAccepted;
	}

	@Override
	protected void creationAborted() {
		super.creationAborted();
	}
}
